package com.ac.scum.log.web.model.ftp.service;

import com.ac.common.core.exception.BaseException;
import com.ac.common.core.exception.config.ExceptionType;
import com.ac.scum.log.bean.Player;
import com.ac.scum.log.web.model.ftp.controller.vo.LogVO;
import com.ac.scum.log.web.model.ftp.mapper.*;
import com.ac.scum.log.web.model.player.mapper.PlayerMapper;
import com.ac.scum.log.web.utils.user.CurrentUserUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
@Service
@AllArgsConstructor
public class ServerFTPFileLogService {
    private final PlayerMapper playerMapper;
    private final ServerFTPLogBankMapper serverFTPLogBankMapper;
    private final ServerFTPLogChatMapper serverFTPLogChatMapper;
    private final ServerFTPLogFlagMapper serverFTPLogFlagMapper;
    private final ServerFTPLogKillMapper serverFTPLogKillMapper;
    private final ServerFTPLogLockMapper serverFTPLogLockMapper;
    private final ServerFTPLogTrapMapper serverFTPLogTrapMapper;
    private final ServerFTPLogAdminMapper serverFTPLogAdminMapper;
    private final ServerFTPLogChestMapper serverFTPLogChestMapper;
    private final ServerFTPLogLoginMapper serverFTPLogLoginMapper;
    private final ServerFTPLogTradeMapper serverFTPLogTradeMapper;
    private final ServerFTPLogRenameMapper serverFTPLogRenameMapper;
    private final ServerFTPLogBunkerMapper serverFTPLogBunkerMapper;
    private final ServerFTPLogVehicleMapper serverFTPLogVehicleMapper;
    private final ServerFTPLogViolationMapper serverFTPLogViolationMapper;
    private final ServerFTPLogExplosivesMapper serverFTPLogExplosivesMapper;
    private final ServerFTPLogBombDefusalMapper serverFTPLogBombDefusalMapper;
    private final ServerFTPLogBunkerActiveMapper serverFTPLogBunkerActiveMapper;
    private final ServerFTPLogChestOwnershipMapper serverFTPLogChestOwnershipMapper;
    private final Pattern steamIdPattern = Pattern.compile("\\d{17}");

    @SuppressWarnings({"unchecked", "rawtypes"})
    public <T> Object findPageByStage(Integer current, Integer size, LogVO vo) throws BaseException {
        if (current <= 0 || size <= 0) {
            throw new BaseException(ExceptionType.Parameter_Error.of("Invalid page or size parameters"));
        }
        Long currentServerId = CurrentUserUtil.getCurrentServerId();
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        BaseMapper baseMapper = getMapperByStage(vo.getStage());
        handleWhereConditions(vo.getWhere(), queryWrapper);
        handleOrderByConditions(vo.getOrder(), queryWrapper);
        queryWrapper.eq("server_id", currentServerId);
        IPage<?> iPage = baseMapper.selectPage(new Page(current, size), queryWrapper);
        Matcher matcher = steamIdPattern.matcher(iPage.getRecords().toString());
        List<Long> steamIds = Lists.newArrayList();
        while (matcher.find()) {
            steamIds.add(Long.parseLong(matcher.group()));
        }
        List<Player> players = playerMapper.findPlayerByServerIdAndSteamIds(currentServerId, steamIds);
        Map<String, Object> map = Maps.newHashMap();
        map.put("players", players);
        map.put("page", iPage);
        return map;
    }

    private BaseMapper<?> getMapperByStage(String stage) throws BaseException {
        return switch (stage) {
            case "bank" -> serverFTPLogBankMapper;
            case "chat" -> serverFTPLogChatMapper;
            case "flag" -> serverFTPLogFlagMapper;
            case "kill" -> serverFTPLogKillMapper;
            case "trap" -> serverFTPLogTrapMapper;
            case "lock" -> serverFTPLogLockMapper;
            case "chest" -> serverFTPLogChestMapper;
            case "admin" -> serverFTPLogAdminMapper;
            case "login" -> serverFTPLogLoginMapper;
            case "trade" -> serverFTPLogTradeMapper;
            case "bunker" -> serverFTPLogBunkerMapper;
            case "vehicle" -> serverFTPLogVehicleMapper;
            case "rename" -> serverFTPLogRenameMapper;
            case "bomb" -> serverFTPLogBombDefusalMapper;
            case "violation" -> serverFTPLogViolationMapper;
            case "explosives" -> serverFTPLogExplosivesMapper;
            case "bunkerActive" -> serverFTPLogBunkerActiveMapper;
            case "chestOwnership" -> serverFTPLogChestOwnershipMapper;
            default -> throw new BaseException(ExceptionType.Parameter_Error.of("Invalid stage: " + stage));

        };
    }

    private <T> void handleWhereConditions(Map<String, List<Map<String, Object>>> where, QueryWrapper<T> queryWrapper) {
        if (where != null) {
            for (Map.Entry<String, List<Map<String, Object>>> entry : where.entrySet()) {
                String conditionType = entry.getKey().toLowerCase();
                for (Map<String, Object> column : entry.getValue()) {
                    if (column.isEmpty()) {
                        continue;
                    }
                    for (Map.Entry<String, Object> condition : column.entrySet()) {
                        Object value = condition.getValue();
                        if (value == null || value.toString().isBlank()) {
                            continue;
                        }
                        switch (conditionType) {
                            case "in" -> {
                                if (value instanceof List<?> valueList) {
                                    if (!valueList.isEmpty()) {
                                        queryWrapper.in(condition.getKey(), valueList.toArray());
                                    }
                                } else {
                                    queryWrapper.in(condition.getKey(), value);
                                }
                            }
                            case "eq" -> queryWrapper.eq(condition.getKey(), value);
                            case "like" -> queryWrapper.like(condition.getKey(), value);
                            case "gt" -> queryWrapper.gt(condition.getKey(), value);
                            case "lt" -> queryWrapper.lt(condition.getKey(), value);
                        }
                    }
                }
            }
        }
    }

    private <T> void handleOrderByConditions(Map<String, List<String>> orderBy, QueryWrapper<T> queryWrapper) {
        if (orderBy != null) {
            for (Map.Entry<String, List<String>> entry : orderBy.entrySet()) {
                String orderType = entry.getKey();
                for (String column : entry.getValue()) {
                    switch (orderType.toLowerCase()) {
                        case "asc":
                            queryWrapper.orderByAsc(column);
                            break;
                        case "desc":
                            queryWrapper.orderByDesc(column);
                            break;
                    }
                }
            }
        }
    }
}
